package blue.base.internal.core.net.channel;

import blue.base.core.net.ChannelHandler;
import blue.base.core.net.Pipeline;
import blue.base.core.util.AssertUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Jin Zheng
 * @since 2021-06-30
 */
public class DefaultPipeline implements Pipeline {
	private static Logger logger = LoggerFactory.getLogger(DefaultPipeline.class);

	private final Map<Class<?>, ChannelHandler> handlerMap = new HashMap<>();
	private final List<ChannelHandler> handlerList = new ArrayList<>();

	public DefaultPipeline() {
	}

	@Override
	public void addLast(ChannelHandler handler) {
		AssertUtil.notNull(handler, "ChannelHandler");
		handlerList.add(handler);
	}

	@Override
	public void addFirst(ChannelHandler handler) {
		AssertUtil.notNull(handler, "ChannelHandler");
		handlerList.add(0, handler);
	}

	@Override
	public void addBefore(Class<?> handlerClass, ChannelHandler handler) {
		AssertUtil.notNull(handlerClass, "ChannelHandler class");
		AssertUtil.notNull(handler, "ChannelHandler");
		int idx = 0;
		for (var h : handlerList) {
			if (h.getClass() == handlerClass) {
				break;
			}
			idx++;
		}
		if (idx == 0) {
			handlerList.add(0, handler);
		} else {
			handlerList.add(idx, handler);
		}
	}

	@Override
	public void addAfter(Class<?> handlerClass, ChannelHandler handler) {
		AssertUtil.notNull(handlerClass, "ChannelHandler class");
		AssertUtil.notNull(handler, "ChannelHandler");
		int idx = 0;
		for (var h : handlerList) {
			if (h.getClass() == handlerClass) {
				break;
			}
			idx++;
		}
		if (idx < handlerList.size() - 1) {
			handlerList.add(idx + 1, handler);
		} else {
			handlerList.add(handler);
		}
	}

	@Override
	public boolean remove(ChannelHandler handler) {
		AssertUtil.notNull(handler, "ChannelHandler");
		var it = handlerList.iterator();
		while (it.hasNext()) {
			var h = it.next();
			if (h == handler) {
				it.remove();
				return true;
			}
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends ChannelHandler> T remove(Class<T> handlerClass) {
		AssertUtil.notNull(handlerClass, "ChannelHandler class");
		var it = handlerList.iterator();
		while (it.hasNext()) {
			var h = it.next();
			if (h.getClass() == handlerClass) {
				it.remove();
				return (T) h;
			}
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends ChannelHandler> T get(Class<T> handlerClass) {
		AssertUtil.notNull(handlerClass, "ChannelHandler class");
		for (var h : handlerList) {
			if (h.getClass() == handlerClass) {
				return (T) h;
			}
		}
		return null;
	}

	@Override
	public List<ChannelHandler> getAll() {
		return List.copyOf(handlerList);
	}
}
